//---------------------------------------------------------------------------
// <copyright file="RibbonToolTip.cs" company="Microsoft Corporation">
//     Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//---------------------------------------------------------------------------

namespace Microsoft.Windows.Controls.Ribbon
{
    #region Using declarations

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Media;

    #endregion

    /// <summary>
    ///   Implements Ribbon's special style of ToolTip.  RibbonToolTip pulls information
    ///   from the Ribbon controls RibbonCommand and lays itself out appropriately.
    /// </summary>
    public class RibbonToolTip : ToolTip
    {
        #region Fields

        /// <summary>
        ///   The vertical offset below the Ribbon at which the tooltip should be positioned.
        /// </summary>
        private const double ToolTipOffsetBelowRibbon = 5.0;
        
        #endregion

        #region Constructors

        /// <summary>
        ///   Initializes static members of the RibbonToolTip class.  This overrides
        ///   the default style.
        /// </summary>
        static RibbonToolTip()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonToolTip), new FrameworkPropertyMetadata(typeof(RibbonToolTip)));
        }

        /// <summary>
        ///   Initializes a new instance of the RibbonToolTip class.  This is where we
        ///   pull values from the controls RibbonCommand.
        /// </summary>
        /// <param name="command">The RibbonCommand to use for initialization.</param>
        public RibbonToolTip(RibbonCommand command)
        {
            this.Title = command.ToolTipTitle;
            this.Description = command.ToolTipDescription;
            this.ImageSource = command.ToolTipImageSource;

            if (!string.IsNullOrEmpty(command.ToolTipFooterTitle) ||
                !string.IsNullOrEmpty(command.ToolTipFooterDescription) ||
                command.ToolTipFooterImageSource != null)
            {
                this.HasFooter = true;
                this.FooterTitle = command.ToolTipFooterTitle;
                this.FooterDescription = command.ToolTipFooterDescription;
                this.FooterImageSource = command.ToolTipFooterImageSource;
            }

            this.Placement = PlacementMode.Custom;
            this.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(this.PlaceRibbonToolTip);
        }

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets or sets the Title property.
        /// </summary>
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        /// <summary>
        ///   Using a DependencyProperty as the backing store for TitleProperty.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(RibbonToolTip));

        /// <summary>
        ///   Gets or sets the Description property.
        /// </summary>
        public string Description
        {
            get { return (string)GetValue(DescriptionProperty); }
            set { SetValue(DescriptionProperty, value); }
        }

        /// <summary>
        ///   Using a DependencyProperty as the backing store for DescriptionProperty.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty DescriptionProperty =
            DependencyProperty.Register("Description", typeof(string), typeof(RibbonToolTip));

        /// <summary>
        ///   Gets or sets the ImageSource property.
        /// </summary>
        public ImageSource ImageSource
        {
            get { return (ImageSource)GetValue(ImageSourceProperty); }
            set { SetValue(ImageSourceProperty, value); }
        }

        /// <summary>
        ///   Using a DependencyProperty as the backing store for ImageSourceProperty.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty ImageSourceProperty =
            DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(RibbonToolTip));

        /// <summary>
        ///   Gets or sets the FooterTitle property.
        /// </summary>
        public string FooterTitle
        {
            get { return (string)GetValue(FooterTitleProperty); }
            set { SetValue(FooterTitleProperty, value); }
        }

        /// <summary>
        ///   Using a DependencyProperty as the backing store for FooterTitleProperty.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty FooterTitleProperty =
            DependencyProperty.Register("FooterTitle", typeof(string), typeof(RibbonToolTip));

        /// <summary>
        ///   Gets or sets the FooterDescription property.
        /// </summary>
        public string FooterDescription
        {
            get { return (string)GetValue(FooterDescriptionProperty); }
            set { SetValue(FooterDescriptionProperty, value); }
        }

        /// <summary>
        ///   Using a DependencyProperty as the backing store for FooterDescriptionProperty.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty FooterDescriptionProperty =
            DependencyProperty.Register("FooterDescription", typeof(string), typeof(RibbonToolTip));

        /// <summary>
        ///   Gets or sets the FooterImageSource property.
        /// </summary>
        public ImageSource FooterImageSource
        {
            get { return (ImageSource)GetValue(FooterImageSourceProperty); }
            set { SetValue(FooterImageSourceProperty, value); }
        }

        /// <summary>
        ///   Using a DependencyProperty as the backing store for FooterImageSourceProperty.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty FooterImageSourceProperty =
            DependencyProperty.Register("FooterImageSource", typeof(ImageSource), typeof(RibbonToolTip));

        /// <summary>
        ///   Gets a value indicating whether the RibbonToolTip has a footer.
        /// </summary>
        public bool HasFooter
        {
            get { return (bool)GetValue(HasFooterProperty); }
            internal set { SetValue(HasFooterProperty, value); }
        }

        /// <summary>
        ///   Using a DependencyProperty as the backing store for HasFooterProperty.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty HasFooterProperty =
            DependencyProperty.Register("HasFooter", typeof(bool), typeof(RibbonToolTip), new UIPropertyMetadata(false));

        #endregion

        #region Public Methods

        /// <summary>
        ///     The Office Fluent UI Guidelines state that ScreenTips must be displayed 5 pixels (at 96dpi)
        ///     below the ribbon, and left aligned with the control emitting the ScreenTip.
        /// </summary>
        /// <param name="popupSize">The size of the popup.</param>
        /// <param name="targetSize">The size of the placement target.</param>
        /// <param name="offset">The Point computed from the HorizontalOffset and VerticalOffset property values.</param>
        /// <returns>An array of possible tooltip placements.</returns>
        public CustomPopupPlacement[] PlaceRibbonToolTip(Size popupSize, Size targetSize, Point offset)
        {
            // Walk up the tree from PlacementTarget (the control emitting the ToolTip) until
            // the Ribbon is found.  Then calculate the y-offset which is 5 pixels below the bottom
            // of the Ribbon.
            FrameworkElement parent = this.PlacementTarget as FrameworkElement;
            while (parent != null && !(parent is Ribbon))
            {
                parent = (FrameworkElement) VisualTreeHelper.GetParent(parent);
            }

            Ribbon ribbon = parent as Ribbon;
            double belowRibbonOffsetY = double.NaN;
            double aboveRibbonOffsetY = double.NaN;
            if (ribbon != null && ribbon.IsAncestorOf(this.PlacementTarget))
            {
                MatrixTransform transform = ribbon.TransformToDescendant(this.PlacementTarget) as MatrixTransform;
                if (transform != null)
                {
                    belowRibbonOffsetY = ribbon.ActualHeight + ToolTipOffsetBelowRibbon + transform.Value.OffsetY;
                    aboveRibbonOffsetY = transform.Value.OffsetY - this.ActualHeight;
                }
            }
            else
            {
                return new CustomPopupPlacement[] { new CustomPopupPlacement(new Point(0, this.ActualHeight), PopupPrimaryAxis.Vertical) };
            }

            // This is the standard placement, below the ribbon.
            CustomPopupPlacement placement = new CustomPopupPlacement(new Point(0, belowRibbonOffsetY), PopupPrimaryAxis.Vertical);

            // This is a fallback placement, if the tooltip will not fit below the ribbon, place it above the ribbon window.
            CustomPopupPlacement placement2 = new CustomPopupPlacement(new Point(0, aboveRibbonOffsetY), PopupPrimaryAxis.Vertical);

            return new CustomPopupPlacement[] { placement, placement2 };
        }

        #endregion
    }
}